package com.liangxy.news.repository;

import android.content.Context;
import android.util.Log;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

import com.liangxy.news.api.ApiClient;
import com.liangxy.news.api.NewsApiService;
import com.liangxy.news.api.NewsResponse;
import com.liangxy.news.database.AppDatabase;
import com.liangxy.news.database.NewsDao;
import com.liangxy.news.database.NewsDetailDao;
import com.liangxy.news.database.UserFollowNewsDao;
import com.liangxy.news.model.News;
import com.liangxy.news.model.NewsDetail;
import com.liangxy.news.model.UserFollowNews;
import com.liangxy.news.util.MockDataProvider;
import com.liangxy.news.util.SharedPreferencesManager;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.internal.EverythingIsNonNull;

/**
 * Repository for news data
 * Manages data from API and local database
 */
public class NewsRepository {
    private static final String TAG = "NewsRepository";
    private static NewsRepository instance;

    // 新闻类型常量
    public static final String TYPE_TOP = "top";        // 头条
    public static final String TYPE_GUONEI = "guonei";  // 国内
    public static final String TYPE_GUOJI = "guoji";    // 国际
    public static final String TYPE_YULE = "yule";      // 娱乐
    public static final String TYPE_TIYU = "tiyu";      // 体育
    public static final String TYPE_JUNSHI = "junshi";  // 军事
    public static final String TYPE_KEJI = "keji";      // 科技
    public static final String TYPE_CAIJING = "caijing"; // 财经
    public static final String TYPE_SHISHANG = "shishang"; // 时尚
    
    private final NewsApiService apiService;
    private final NewsDao newsDao;
    private final NewsDetailDao newsDetailDao;
    private final UserFollowNewsDao userFollowNewsDao;
    private final ExecutorService executorService;
    private final MutableLiveData<Boolean> isLoading = new MutableLiveData<>(false);
    private final MutableLiveData<String> errorMessage = new MutableLiveData<>(null);
    private final SharedPreferencesManager preferencesManager;
    
    // 控制是否使用模拟数据
    private boolean useMockData = false;
    
    private NewsRepository(Context context) {
        AppDatabase database = AppDatabase.getInstance(context);
        newsDao = database.newsDao();
        newsDetailDao = database.newsDetailDao();
        userFollowNewsDao = database.userFollowNewsDao();
        apiService = ApiClient.getNewsApiService();
        executorService = Executors.newFixedThreadPool(4);
        preferencesManager = new SharedPreferencesManager(context);
        
        // 检查是否应该使用模拟数据
        useMockData = preferencesManager.getBoolean("use_mock_data", false);
    }
    
    /**
     * Get instance of NewsRepository
     * @param context Application context
     * @return NewsRepository instance
     */
    public static synchronized NewsRepository getInstance(Context context) {
        if (instance == null) {
            instance = new NewsRepository(context);
        }
        return instance;
    }
    
    /**
     * 设置是否使用模拟数据
     * @param useMock 是否使用模拟数据
     */
    public void setUseMockData(boolean useMock) {
        this.useMockData = useMock;
        preferencesManager.saveBoolean("use_mock_data", useMock);
    }
    
    /**
     * 是否使用模拟数据
     * @return 是否使用模拟数据
     */
    public boolean isUsingMockData() {
        return useMockData;
    }
    
    public LiveData<Boolean> getIsLoading() {
        return isLoading;
    }
    
    public LiveData<String> getErrorMessage() {
        return errorMessage;
    }
    
    /**
     * Get news from API and save to database
     * @param category News category
     * @param page Page number
     * @param pageSize Page size
     * @param forceRefresh Whether to force refresh from API
     * @return LiveData list of news
     */
    public LiveData<List<News>> getNewsByCategory(String category, int page, int pageSize, boolean forceRefresh) {
        // 返回数据库中的缓存数据
        LiveData<List<News>> cachedNews = newsDao.getNewsByCategory(category);
        
        // 如果需要强制刷新或数据库中没有数据，从API获取
        if (forceRefresh) {
            refreshNewsByCategory(category, page, pageSize);
        }
        
        return cachedNews;
    }
    
    /**
     * Refresh news from API
     * @param category News category
     * @param page Page number
     * @param pageSize Page size
     */
    public void refreshNewsByCategory(String category, int page, int pageSize) {
        if (useMockData) {
            // 使用模拟数据
            handleMockNewsResponse(MockDataProvider.getNewsList(category), category);
            return;
        }
        
        isLoading.postValue(true);
        errorMessage.postValue(null);
        
        // 从API获取新闻数据
        apiService.getNewsList(ApiClient.getApiKey(), category, page, pageSize, 1).enqueue(new Callback<NewsResponse>() {
            @Override
            public void onResponse(Call<NewsResponse> call, Response<NewsResponse> response) {
                isLoading.postValue(false);
                if (response.isSuccessful() && response.body() != null) {
                    NewsResponse newsResponse = response.body();
                    if (newsResponse.getErrorCode() == 0 && newsResponse.getResult() != null) {
                        List<News> newsList = newsResponse.getResult().getData();
                        if (newsList != null) {
                            // 设置新闻分类和来源
                            for (News news : newsList) {
                                if (news.getCategory() == null || news.getCategory().isEmpty()) {
                                    news.setCategory(category);
                                }
                                news.setSource("聚合数据");
                            }
                            // 保存到数据库
                            saveNews(newsList);
                            Log.d(TAG, "成功从API获取 " + newsList.size() + " 条新闻");
                        }
                    } else {
                        errorMessage.postValue("API错误: " + newsResponse.getReason());
                        Log.e(TAG, "API错误: " + newsResponse.getReason());
                        
                        // 只有在用户设置使用模拟数据时才使用模拟数据
                        if (useMockData) {
                            handleMockNewsResponse(MockDataProvider.getNewsList(category), category);
                        }
                    }
                } else {
                    errorMessage.postValue("网络请求失败");
                    Log.e(TAG, "网络请求失败: " + response.code());
                    
                    // 只有在用户设置使用模拟数据时才使用模拟数据
                    if (useMockData) {
                        handleMockNewsResponse(MockDataProvider.getNewsList(category), category);
                    }
                }
            }
            
            @Override
            public void onFailure(Call<NewsResponse> call, Throwable t) {
                isLoading.postValue(false);
                errorMessage.postValue("网络请求失败: " + t.getMessage());
                Log.e(TAG, "网络请求失败", t);
                
                // 只有在用户设置使用模拟数据时才使用模拟数据
                if (useMockData) {
                    handleMockNewsResponse(MockDataProvider.getNewsList(category), category);
                }
            }
        });
    }
    
    /**
     * 处理模拟新闻响应
     * @param newsResponse 模拟新闻响应
     * @param category 新闻分类
     */
    private void handleMockNewsResponse(NewsResponse newsResponse, String category) {
        isLoading.postValue(false);
        Log.d(TAG, "处理模拟数据响应，分类: " + category);
        
        if (newsResponse != null && newsResponse.getResult() != null) {
            List<News> newsList = newsResponse.getResult().getData();
            if (newsList != null && !newsList.isEmpty()) {
                Log.d(TAG, "收到模拟数据: " + newsList.size() + " 条新闻");
                
                // 设置新闻分类
                for (News news : newsList) {
                    if (news.getCategory() == null || news.getCategory().isEmpty()) {
                        news.setCategory(category);
                    }
                    // 确保设置了来源
                    if (news.getSource() == null || news.getSource().isEmpty()) {
                        news.setSource("模拟数据");
                    }
                }
                
                // 保存到数据库
                saveNews(newsList);
                Log.d(TAG, "模拟数据已保存到数据库");
            } else {
                Log.w(TAG, "模拟数据为空或无效");
                errorMessage.postValue("无法加载模拟数据");
            }
        } else {
            Log.e(TAG, "模拟数据响应无效");
            errorMessage.postValue("模拟数据响应无效");
        }
    }
    
    /**
     * Get followed news for a user
     * @param userId User ID
     * @return LiveData list of followed news
     */
    public LiveData<List<News>> getFollowedNews(String userId) {
        try {
            if (userId == null || userId.isEmpty()) {
                return newsDao.getFollowedNews();
            }
            return userFollowNewsDao.getFollowedNews(userId);
        } catch (Exception e) {
            Log.e(TAG, "获取关注新闻失败: " + e.getMessage(), e);
            // 返回空列表
            MutableLiveData<List<News>> emptyList = new MutableLiveData<>();
            emptyList.postValue(new ArrayList<>());
            return emptyList;
        }
    }
    
    /**
     * Follow a news
     * @param userId User ID
     * @param newsId News ID
     */
    public void followNews(String userId, String newsId) {
        if (userId == null || userId.isEmpty() || newsId == null || newsId.isEmpty()) {
            Log.e(TAG, "followNews: 参数无效 userId=" + userId + ", newsId=" + newsId);
            return;
        }
        
        executorService.execute(() -> {
            try {
                synchronized (NewsRepository.class) {
                    // 更新关联表
                    UserFollowNews userFollowNews = new UserFollowNews(userId, newsId, System.currentTimeMillis());
                    userFollowNewsDao.insert(userFollowNews);
                    
                    // 更新新闻表中的标记
                    newsDao.setNewsFollowed(newsId, true);
                    
                    // 确保数据已写入
                    AppDatabase.getInstance(null).getOpenHelper().getWritableDatabase().execSQL("PRAGMA wal_checkpoint(PASSIVE)");
                    
                    Log.d(TAG, "新闻关注成功: userId=" + userId + ", newsId=" + newsId);
                }
            } catch (Exception e) {
                Log.e(TAG, "关注新闻时出错: " + e.getMessage(), e);
            }
        });
    }
    
    /**
     * Unfollow a news
     * @param userId User ID
     * @param newsId News ID
     */
    public void unfollowNews(String userId, String newsId) {
        if (userId == null || userId.isEmpty() || newsId == null || newsId.isEmpty()) {
            Log.e(TAG, "unfollowNews: 参数无效 userId=" + userId + ", newsId=" + newsId);
            return;
        }
        
        executorService.execute(() -> {
            try {
                synchronized (NewsRepository.class) {
                    // 删除关联表中的记录
                    userFollowNewsDao.deleteByUserAndNews(userId, newsId);
                    
                    // 更新新闻表中的标记
                    newsDao.setNewsFollowed(newsId, false);
                    
                    // 确保数据已写入
                    AppDatabase.getInstance(null).getOpenHelper().getWritableDatabase().execSQL("PRAGMA wal_checkpoint(PASSIVE)");
                    
                    Log.d(TAG, "取消关注新闻成功: userId=" + userId + ", newsId=" + newsId);
                }
            } catch (Exception e) {
                Log.e(TAG, "取消关注新闻时出错: " + e.getMessage(), e);
            }
        });
    }
    
    /**
     * Check if user follows a news
     * @param userId User ID
     * @param newsId News ID
     * @return Whether the user follows the news
     */
    public boolean isFollowing(String userId, String newsId) {
        if (userId == null || userId.isEmpty() || newsId == null || newsId.isEmpty()) {
            return false;
        }
        
        try {
            // 使用同步方法从newsDao中获取新闻状态
            News news = newsDao.getNewsById(newsId);
            // 如果新闻对象存在，直接返回其关注状态
            if (news != null) {
                return news.isFollowed();
            }
        } catch (Exception e) {
            Log.e(TAG, "检查关注状态时出错: " + e.getMessage(), e);
        }
        
        return false;
    }
    
    /**
     * Check if user follows a news (non-blocking version that uses callback)
     * @param userId User ID
     * @param newsId News ID
     * @param callback Callback to receive the result
     */
    public void isFollowingAsync(String userId, String newsId, FollowCallback callback) {
        if (userId == null || userId.isEmpty() || newsId == null || newsId.isEmpty()) {
            if (callback != null) {
                callback.onResult(false);
            }
            return;
        }
        
        executorService.execute(() -> {
            try {
                News news = newsDao.getNewsById(newsId);
                boolean isFollowed = news != null && news.isFollowed();
                
                if (callback != null) {
                    callback.onResult(isFollowed);
                }
            } catch (Exception e) {
                Log.e(TAG, "检查关注状态时出错: " + e.getMessage(), e);
                if (callback != null) {
                    callback.onResult(false);
                }
            }
        });
    }
    
    /**
     * Callback interface for async follow status
     */
    public interface FollowCallback {
        void onResult(boolean isFollowed);
    }
    
    /**
     * Record that a user has read a news
     * @param newsId News ID
     */
    public void recordNewsRead(String newsId) {
        executorService.execute(() -> {
            newsDao.updateNewsLastReadTime(newsId, System.currentTimeMillis());
        });
    }
    
    /**
     * Get news reading history
     * @return LiveData list of news history
     */
    public LiveData<List<News>> getNewsHistory() {
        return newsDao.getNewsHistory();
    }
    
    /**
     * Save news to database
     * @param newsList List of news to save
     */
    private void saveNews(List<News> newsList) {
        executorService.execute(() -> {
            try {
                synchronized (NewsRepository.class) {
                    Log.d(TAG, "开始保存 " + newsList.size() + " 条新闻到数据库");
                    List<News> updatedNewsList = new ArrayList<>();
                    List<NewsDetail> newsDetailsToCreate = new ArrayList<>();
                    
                    for (News news : newsList) {
                        // 数据有效性验证
                        if (news == null || news.getUniquekey() == null || news.getUniquekey().isEmpty()) {
                            Log.w(TAG, "跳过无效新闻：没有ID");
                            continue;
                        }
                        
                        // 从数据库获取已存在的新闻
                        News existingNews = newsDao.getNewsById(news.getUniquekey());
                        if (existingNews != null) {
                            // 保留关注状态和上次阅读时间
                            news.setFollowed(existingNews.isFollowed());
                            news.setLastReadTime(existingNews.getLastReadTime());
                            
                            // 保留详细内容（如果已存在）
                            if (existingNews.isIs_content() && existingNews.getContent() != null && !existingNews.getContent().isEmpty()) {
                                news.setContent(existingNews.getContent());
                                news.setIs_content(true);
                            }
                            
                            Log.d(TAG, "更新已存在的新闻: " + news.getTitle());
                        } else {
                            Log.d(TAG, "添加新的新闻: " + news.getTitle());
                            
                            // 检查是否需要为新闻创建一个对应的详情记录
                            NewsDetail existingDetail = newsDetailDao.getNewsDetailByNewsId(news.getUniquekey());
                            if (existingDetail == null) {
                                // 创建一个基本的详情记录，这样每个新闻至少有一个详情记录
                                NewsDetail defaultDetail = createDefaultNewsDetail(news);
                                newsDetailsToCreate.add(defaultDetail);
                                Log.d(TAG, "为新闻创建默认详情记录: " + news.getUniquekey());
                            }
                        }
                        updatedNewsList.add(news);
                    }
                    
                    // 批量插入或更新新闻
                    newsDao.insertAll(updatedNewsList);
                    
                    // 批量插入新闻详情
                    if (!newsDetailsToCreate.isEmpty()) {
                        for (NewsDetail detail : newsDetailsToCreate) {
                            newsDetailDao.insert(detail);
                        }
                        Log.d(TAG, "成功创建 " + newsDetailsToCreate.size() + " 条新闻详情记录");
                    }
                    
                    // 确保数据写入磁盘
                    AppDatabase.getInstance(null).getOpenHelper().getWritableDatabase().execSQL("PRAGMA wal_checkpoint(PASSIVE)");
                    
                    Log.d(TAG, "成功保存 " + updatedNewsList.size() + " 条新闻到数据库");
                }
            } catch (Exception e) {
                Log.e(TAG, "保存新闻到数据库时出错: " + e.getMessage(), e);
                errorMessage.postValue("保存数据失败: " + e.getMessage());
            }
        });
    }
    
    /**
     * 为新闻创建默认的详情记录
     * @param news 新闻对象
     * @return 新闻详情对象
     */
    private NewsDetail createDefaultNewsDetail(News news) {
        String title = news.getTitle() != null ? news.getTitle() : "未知标题";
        String date = news.getDate() != null ? news.getDate() : "未知日期";
        String author = news.getAuthorName() != null ? news.getAuthorName() : "未知来源";
        
        // 创建一个基本的HTML内容
        StringBuilder contentBuilder = new StringBuilder();
        contentBuilder.append("<h1>").append(title).append("</h1>");
        
        // 添加图片（如果有）
        if (news.getThumbnail_pic_s() != null && !news.getThumbnail_pic_s().isEmpty()) {
            contentBuilder.append("<div style='text-align:center;margin:15px 0;'>");
            contentBuilder.append("<img src='").append(news.getThumbnail_pic_s()).append("' style='max-width:100%;' alt='新闻图片'>");
            contentBuilder.append("</div>");
        }
        
        // 添加一些基本信息
        contentBuilder.append("<p>来源: ").append(author).append("</p>");
        contentBuilder.append("<p>日期: ").append(date).append("</p>");
        
        // 添加一个提示信息
        contentBuilder.append("<p style='margin-top:20px;color:#888;'>点击刷新按钮获取完整内容...</p>");
        
        // 创建详情对象
        return new NewsDetail(
                news.getUniquekey(),
                title,
                date,
                author,
                contentBuilder.toString()
        );
    }
    
    /**
     * 刷新新闻详情数据
     * @param newsId 新闻ID
     * @param forceRefresh 是否强制刷新
     */
    public void refreshNewsDetail(String newsId, boolean forceRefresh) {
        if (newsId == null || newsId.isEmpty()) {
            Log.e(TAG, "无效的新闻ID");
            return;
        }
        
        Log.d(TAG, "刷新新闻详情: " + newsId + ", 强制刷新: " + forceRefresh);
        
        // 首先从数据库查询
        executorService.execute(() -> {
            try {
                boolean shouldFetchFromApi = true;
                
                if (!forceRefresh) {
                    // 检查数据库中是否已有详情
                    NewsDetail localDetail = AppDatabase.getInstance(null).newsDetailDao().getNewsDetailByNewsId(newsId);
                    
                    if (localDetail != null && localDetail.getContent() != null && !localDetail.getContent().isEmpty()) {
                        // 本地已有数据且内容不为空，无需从API获取
                        shouldFetchFromApi = false;
                        Log.d(TAG, "数据库中已有新闻详情，内容长度: " + localDetail.getContent().length());
                    } else {
                        Log.d(TAG, "数据库中没有完整的新闻详情或内容为空");
                    }
                }
                
                if (shouldFetchFromApi) {
                    // 需要从API获取
                    Log.d(TAG, "从API获取新闻详情: " + newsId);
                    // 此处可以使用NewsDetailViewModel中的方法获取详情
                }
            } catch (Exception e) {
                Log.e(TAG, "刷新新闻详情时出错: " + e.getMessage(), e);
            }
        });
    }
} 